﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.CustomProperties;
using DocumentFormat.OpenXml.VariantTypes;
using Expect.Core;
using System.Reflection;
using Expect.Core.Interfaces;
using Expect.Core.Fixtures;

namespace Expect.Report.Word.Processors
{
    public class DefaultProcessor : IProcessor
    {
        public Assembly TargetAssembly { get; set; }

        public Func<string, string> ResolveStyle { get; set; }
        
        public ReportConfiguration Configuration { get; set; }
        
        public WordprocessingDocument Document { get; set; }

        public Core.FixtureDefinition Fixture { get; set; }
        
        public virtual void Apply()
        {
            if (Fixture.HasClass && Fixture.ClassType.GetInterfaces().Any(t => t == typeof(ITableFixtureFormat)))
            {
                GenerateTableFixture();
            }
            else
            {
                GenerateTextFixture(Configuration.SpecificationsStyle);
            }
        }
        
        public void GenerateTextFixture(string stylename)
        {
            if (Fixture.HasClass && Fixture.Definition != null)
            {
                WriteFixtureMethodRow(Fixture.Definition, stylename);
            }
            foreach (var row in Fixture.Rows)
            {
                WriteFixtureMethodRow(row, stylename);
            }
        }

        public void WriteFixtureMethodRow(FixtureRow row, string stylename)
        {
            var par = Document.NewParagraph(ResolveStyle(stylename));
            if (row.Cells.Count == 1)
            {
                this.AddText(par, row.Cells[0].Text);
                return;
            }

            for (int i = 0; i < row.Cells.Count; i++)
            {
                if (i % 2 == 0)
                {
                    if (i == 0)
                        this.AddText(par, row.Cells[i].Text + " ");
                    else if (i == row.Cells.Count - 1)
                        this.AddText(par, " " + row.Cells[i].Text);
                    else
                        this.AddText(par, " " + row.Cells[i].Text + " ");
                }
                else
                {
                    this.AddTextParameter(par, row.Cells[i].Text);
                }
            }
        }

        public void AddText(Paragraph pr, string text)
        {
            Run run = new Run();
            run.Append(new Text { Text = text, Space = SpaceProcessingModeValues.Preserve });
            pr.Append(run);
        }

        public void AddTextParameter(Paragraph pr, string text)
        {
            Run run = new Run();
            RunProperties props = new RunProperties();
            if (Configuration.Parameters.Bold)
            {
                Bold bld = new Bold();
                props.Append(bld);
            }
            if (Configuration.Parameters.Underlined)
            {
                Underline underline = new Underline() { Val = UnderlineValues.Single };
                props.Append(underline);
            }
            if (Configuration.Parameters.Italic)
            {
                Italic italic = new Italic();
                props.Append(italic);
            }
            run.Append(props);
            run.Append(new Text { Text = text });
            pr.Append(run);
        }        

        public void AddParagraph(string text, int? heading)
        {
            string stylename = GetStyleName(heading);

            Document.AddParagraph(text, ResolveStyle(stylename));
        }

        public string GetStyleName(int? heading)
        {
            return GetStyleName(Configuration, heading);
        }

        public void GenerateTableFixture()
        {
            this.WriteFixtureMethodRow(Fixture.Definition, Configuration.SpecificationsStyle);

            Table tbl = new Table();

            TableProperties tableProperties1 = new TableProperties();

            if (!string.IsNullOrEmpty(Configuration.TablesStyle))
            {
                TableStyle tableStyle1 = new TableStyle() { Val = ResolveStyle(Configuration.TablesStyle) };
                tableProperties1.Append(tableStyle1);
            }

            TableJustification tableJustification1 = new TableJustification() { Val = TableRowAlignmentValues.Center };
            tableProperties1.Append(tableJustification1);
            tbl.Append(tableProperties1);

            var pr = Document.NewParagraph(ResolveStyle(Configuration.SpecificationsStyle));
            Document.MainDocumentPart.Document.Body.Append(tbl);
            
            for (int i = 0; i < Fixture.Rows.Count; i++)
            {
                TableRow tableRow = new TableRow();
                tbl.Append(tableRow);

                foreach (var cell in Fixture.Rows[i].Cells)
                {
                    TableCell tablecell = new TableCell();
                    tableRow.Append(tablecell);
                    Paragraph par = new Paragraph();
                    Run run1 = new Run();
                    run1.Append(new Text { Text = cell.Text });
                    par.Append(run1);
                    tablecell.Append(par);
                }

                //this.AddParagraph(fixture.Rows[i].AsText());
            }
        }

        public static string GetStyleName(ReportConfiguration conf, int? heading)
        {
            string stylename = null;
            if (heading.HasValue)
            {
                if (heading.Value > conf.HeadingStyles.Length)
                {
                    stylename = conf.HeadingStyles[conf.HeadingStyles.Length - 1];
                }
                else
                {
                    stylename = conf.HeadingStyles[heading.Value];
                }
            }

            return stylename;
        }
    }
}
